#include "stm32f4xx.h"                  // Device header
#include "stm32f4xx_conf.h"
#include "Warming.h"

/*
 *SPI模式选择:
 *
 *CPOL(时钟极性):
 *		0/Low-空闲状态时,SCK=0
 *		1/High-空闲状态时,SCK=1
 *CPHA(时钟相位):
 *		0/1Edge-SCK第一个边沿移入数据,第二个边沿移出数据
 *		1/2Edge-SCK第一个边沿移出数据,第二个边沿移入数据
 *
 *模式0:CPOL=0,CPHA=0
 *模式1:CPOL=0,CPHA=1
 *模式2:CPOL=1,CPHA=0
 *模式3:CPOL=1,CPHA=1
 */

//加速度计寄存器
#define BMI088_ACC_CHIP_ID				0x00//加速度计Who Am I寄存器
#define BMI088_ACC_PWR_CTRL				0x7D//加速度计电源控制寄存器
#define BMI088_ACC_PWR_CONF				0x7C//加速度计电源配置寄存器
#define BMI088_ACC_CONF					0x40//加速度计配置寄存器
#define BMI088_ACC_RANGE				0x41//加速度计范围设置寄存器
#define BMI088_INT1_IO_CONF				0x53//加速度计配置INT1输入输出引脚寄存器
#define BMI088_INT1_INT2_MAP_DATA		0x58//加速度计映射数据就绪中断到INT1/INT2寄存器
#define BMI088_ACC_SOFTRESET			0x7E//加速度计软件重启寄存器
#define BMI088_ACC_AccelDataStart		0x12//加速度计数据寄存器首地址
#define BMI088_ACC_TEMP_MSB				0x22//加速度计温度寄存器高八位
#define BMI088_ACC_TEMP_LSB				0x23//加速度计温度寄存器低三位

//陀螺仪寄存器
#define BMI088_GYRO_CHIP_ID				0x00//陀螺仪Who Am I寄存器
#define BMI088_GYRO_RANGE				0x0F//陀螺仪范围设置寄存器
#define BMI088_GYRO_BANDWIDTH			0x10//陀螺仪带宽寄存器
#define BMI088_GYRO_LPM1				0x11//陀螺仪主电源模式选择寄存器
#define BMI088_GYRO_INT_CTRL			0x15//陀螺仪中断控制寄存器
#define BMI088_INT3_INT4_IO_CONF		0x16//陀螺仪配置中断输入输出引脚寄存器
#define BMI088_INT3_INT4_IO_MAP			0x18//陀螺仪映射数据就绪中断到INT3/INT4寄存器
#define BMI088_GYRO_SOFTRESET			0x14//陀螺仪软件重启寄存器
#define BMI088_GYRO_GyroDataStart		0x02//陀螺仪数据寄存器首地址

#define BMI088_ACC_Address				0x1E//加速度计地址
#define BMI088_GYRO_Address				0x0F//陀螺仪地址


#define BMI088_CS_Accel(x)				GPIO_WriteBit(GPIOA,GPIO_Pin_4,(BitAction)(x))//写加速度计的片选引脚
#define BMI088_CS_Gyro(x)				GPIO_WriteBit(GPIOB,GPIO_Pin_0,(BitAction)(x))//写陀螺仪的片选引脚

#define BMI088_Accel_Start()			BMI088_CS_Accel(0)//BMI088加速度计硬件SPI数据交换开始(拉低BMI088_CS_Accel完成片选)
#define BMI088_Accel_Stop()				BMI088_CS_Accel(1)//BMI088加速度计硬件SPI数据交换结束(拉高BMI088_CS_Accel结束片选)
#define BMI088_Gyro_Start()				BMI088_CS_Gyro(0)//BMI088陀螺仪硬件SPI数据交换开始(拉低BMI088_CS_Gyro完成片选)
#define BMI088_Gyro_Stop()				BMI088_CS_Gyro(1)//BMI088陀螺仪硬件SPI数据交换结束(拉高BMI088_CS_Gyro结束片选)


uint8_t BMI088_SPI_DMASend[8],BMI088_SPI_DMAReceive[8];//BMI088的SPI发送DMA存储器数组,BMI088的SPI接收DMA存储器数组
uint8_t BMI088_FirstDMA_Flag=2,BMI088_DMAAccGyroSelect;//BMI088的DMA首次启动标志位(0-已经首次启动,1-准备首次启动,2-等待首次启动),BMI088的DMA处于加速度计数据接收还是陀螺仪数据接收的状态选择(1-加速度计数据接收,2-陀螺仪数据接收)
uint8_t BMI088_DataStartFlag;//BMI088开始接收数据标志位

int16_t BMI088_RawAccelData[3],BMI088_RawGyroData[3],BMI088_RawTemperatureData;//BMI088的三轴加速度原始数据,三轴角速度原始数据和温度原始数据
float BMI088_Accel[3],BMI088_Gyro[3],BMI088_Temperature;//BMI088的三轴加速度数据,三轴角速度数据和温度

/*
 *函数简介:BMI088专用微秒级延时
 *参数说明:延时时长,单位us
 *返回类型:无
 *备注:参数范围:0~4294967295
 */
void BMI088_Delay_us(uint32_t us)
{		
	uint32_t temp;	    	 
	SysTick->LOAD=us*21; 						//时间加载，我们要延时n倍的us, 1us是一个fac_ua周期，所以总共要延时的周期值为二者相乘最后送到Load中。		 
	SysTick->VAL=0x00;        					//清空计数器
	SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;	//开启使能位 开始倒数
	do temp=SysTick->CTRL;
	while((temp&0x01) && !(temp&(1<<16)));		//用来判断 systick 定时器是否还处于开启状态，然后在等待时间到达，也就是数到0的时候,此时第十六位设置为1
	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;	//关闭计数器使能位
	SysTick->VAL=0x00;       					//清空计数器
}

/*
 *函数简介:BMI088加速度计写寄存器
 *参数说明:8bits寄存器地址
 *参数说明:8bits寄存器写入数据
 *返回类型:无
 *备注:在第一个数据发送时,第二个数据已经在发送缓冲区等待以实现连续数据流
 *备注:BMI088的寄存器地址的最高位bit需要为0(即&0x7F),以实现写寄存器
 */
void BMI088_SPI_AccelWriteRegister(uint8_t RegAddress,uint8_t Data)
{
	BMI088_Accel_Start();//开始
	
	while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)!=SET);//发送缓冲区为空
	SPI_I2S_SendData(SPI1,RegAddress & 0x7F);//将地址(写数据)放入发送缓冲区
	
	while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)!=SET);//发送缓冲区为空
	SPI_I2S_SendData(SPI1,Data);//SPI发送数据(放入发送缓冲区,实现连续数据流)
	
	while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)!=SET);//接收缓冲区非空,即第一个数据(地址数据)移位完成
	SPI_I2S_ReceiveData(SPI1);//此数据来自发送地址,故读取当前接收缓冲区以清除接收数据和标志位
	
	while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)!=SET);//接收缓冲区非空,即第二个数据(接收数据)移位完成
	SPI_I2S_ReceiveData(SPI1);//SPI接收数据,清除接收数据和标志位
	
	BMI088_Accel_Stop();//结束
}

/*
 *函数简介:BMI088加速度计读寄存器
 *参数说明:8bits寄存器地址
 *返回类型:8bits寄存器读出数据
 *备注:在第一个数据发送时,第二个数据已经在发送缓冲区等待以实现连续数据流
 *备注:BMI088的寄存器地址的最高位bit需要为1(即|0x80),以实现读寄存器
 *备注:加速度计读取寄存器时(包括连续读取和非连续读取),第一个读出数据是乱码,从第二个开始才是有效数据
 */
uint8_t BMI088_SPI_AccelReadRegister(uint8_t RegAddress)
{
	BMI088_Accel_Start();//开始
	
	while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)!=SET);//发送缓冲区为空
	SPI_I2S_SendData(SPI1,RegAddress | 0x80);//将地址(读数据)放入发送缓冲区
	
	while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)!=SET);//发送缓冲区为空
	SPI_I2S_SendData(SPI1,0x00);//SPI发送数据(放入发送缓冲区,实现连续数据流)
	while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)!=SET);//接收缓冲区非空,即第一个数据(地址数据)移位完成
	SPI_I2S_ReceiveData(SPI1);//此数据来自发送地址,故读取当前接收缓冲区以清除接收数据和标志位
	
	while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)!=SET);//发送缓冲区为空
	SPI_I2S_SendData(SPI1,0x00);//SPI发送数据(放入发送缓冲区,实现连续数据流)
	while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)!=SET);//接收缓冲区非空,即第二个数据(地址数据)移位完成
	SPI_I2S_ReceiveData(SPI1);//此回传数据为乱码,故读取当前接收缓冲区以清除接收数据和标志位
	
	while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)!=SET);//接收缓冲区非空,即第三个数据(接收数据)移位完成
	BMI088_Accel_Stop();//结束
	
	return SPI_I2S_ReceiveData(SPI1);//SPI接收数据
}

/*
 *函数简介:BMI088陀螺仪写寄存器
 *参数说明:8bits寄存器地址
 *参数说明:8bits寄存器写入数据
 *返回类型:无
 *备注:在第一个数据发送时,第二个数据已经在发送缓冲区等待以实现连续数据流
 *备注:BMI088的寄存器地址的最高位bit需要为0(即&0x7F),以实现写寄存器
 */
void BMI088_SPI_GyroWriteRegister(uint8_t RegAddress,uint8_t Data)
{
	BMI088_Gyro_Start();//开始
	
	while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)!=SET);//发送缓冲区为空
	SPI_I2S_SendData(SPI1,RegAddress & 0x7F);//将地址(写数据)放入发送缓冲区
	
	while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)!=SET);//发送缓冲区为空
	SPI_I2S_SendData(SPI1,Data);//SPI发送数据(放入发送缓冲区,实现连续数据流)
	
	while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)!=SET);//接收缓冲区非空,即第一个数据(地址数据)移位完成
	SPI_I2S_ReceiveData(SPI1);//此数据来自发送地址,故读取当前接收缓冲区以清除接收数据和标志位
	
	while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)!=SET);//接收缓冲区非空,即第二个数据(接收数据)移位完成
	SPI_I2S_ReceiveData(SPI1);//SPI接收数据,清除接收数据和标志位
	
	BMI088_Gyro_Stop();//结束
}

/*
 *函数简介:BMI088陀螺仪读寄存器
 *参数说明:8bits寄存器地址
 *返回类型:8bits寄存器读出数据
 *备注:在第一个数据发送时,第二个数据已经在发送缓冲区等待以实现连续数据流
 *备注:BMI088的寄存器地址的最高位bit需要为1(即|0x80),以实现读寄存器
 */
uint8_t BMI088_SPI_GyroReadRegister(uint8_t RegAddress)
{
	BMI088_Gyro_Start();//开始
	
	while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)!=SET);//发送缓冲区为空
	SPI_I2S_SendData(SPI1,RegAddress | 0x80);//将地址(读数据)放入发送缓冲区
	
	while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)!=SET);//发送缓冲区为空
	SPI_I2S_SendData(SPI1,0x00);//SPI发送数据(放入发送缓冲区,实现连续数据流)
	
	while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)!=SET);//接收缓冲区非空,即第一个数据(地址数据)移位完成
	SPI_I2S_ReceiveData(SPI1);//此数据来自发送地址,故读取当前接收缓冲区以清除接收数据和标志位
	
	while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)!=SET);//接收缓冲区非空,即第二个数据(接收数据)移位完成
	BMI088_Gyro_Stop();//结束
	
	return SPI_I2S_ReceiveData(SPI1);//SPI接收数据
}

/*
 *函数简介:BMI088初始化
 *参数说明:无
 *返回类型:无
 *备注:使用SPI1,SPI模式3(CPOL=1,CPHA=1),波特率5.25MHz
 *备注:规定SPI1_CLK为PB3,SPI1_MISO为PB4,SPI1_MOSI为PA7,CS1_Accel为PA4(加速度计片选引脚),CS1_Gyro为PB0(陀螺仪片选引脚)
 *备注:规定INT1_Accel为PC4,INT1_Gyro为PC5,分别连接芯片的INT1和INT3,配置为数据就绪中断(下降沿)
 *备注:采用SPI收发DMA节约CPU资源(SPI1发送DMA为DMA2数据流3通道3,SPI1接收DMA为DMA2数据流2通道3)
 *备注:在初始化中对寄存器进行了配置,最关键配置为加速度量程±3g,角速度量程±2000°/s
 *备注:配置寄存器时会对加速度计和陀螺仪进行软重启,加速度计耗时1ms,陀螺仪耗时30ms,同时软重启之后第一次读写有bug,数据会错误
 *备注:加速度计软重启之后需要重新上电,需要配置BMI088_ACC_PWR_CTRL和BMI088_ACC_PWR_CONF两个寄存器,每次配置需要等待一段时间,测试得到250us足矣,共耗时500us,保险起见采用300us,共耗时600us
 *备注:保险起见在每一次配置寄存器之后加入300us的延时,共计3.6ms
 *备注:初始化时会检查加速度计和陀螺仪的ID,ID错误会进行报警,并且程序会卡死不断的进行检测,具体报警现象见Warming.h
 */
void BMI088_Init(void)
{
	/*===============配置时钟===============*/
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);//开启时钟
	
	/*===============配置GPIO===============*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT;
	GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推挽输出
	GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;//默认上拉
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);//配置CS1_Accel(加速度计片选引脚)
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
	GPIO_Init(GPIOB,&GPIO_InitStructure);//配置CS1_Gyro(陀螺仪片选引脚)
	
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;//复用推挽
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3 | GPIO_Pin_4;
	GPIO_Init(GPIOB,&GPIO_InitStructure);//配置SPI1_CLK和SPI1_MISO
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_7;
	GPIO_Init(GPIOA,&GPIO_InitStructure);//配置SPI1_MOSI
	
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN;//上拉输入
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4 | GPIO_Pin_5;
	GPIO_Init(GPIOC,&GPIO_InitStructure);//配置INT1_Accel和INT1_Gyro(加速度计和陀螺仪的中断线)
	
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource7,GPIO_AF_SPI1);//开启PA7的SPI1复用模式
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource3,GPIO_AF_SPI1);//开启PB3的SPI1复用模式
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource4,GPIO_AF_SPI1);//开启PB4的SPI1复用模式
	
	/*===============配置SPI和SPI收发DMA===============*/
	SPI_InitTypeDef SPI_InitStructure;
	SPI_InitStructure.SPI_Mode=SPI_Mode_Master;//主机模式
	SPI_InitStructure.SPI_Direction=SPI_Direction_2Lines_FullDuplex;//双线全双工
	SPI_InitStructure.SPI_DataSize=SPI_DataSize_8b;//8位数据帧
	SPI_InitStructure.SPI_FirstBit=SPI_FirstBit_MSB;//高位先行
	SPI_InitStructure.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_8;//波特率预分频系数8,SCK频率为PCLK/分频系数,即Freq_SCK=42MHz/8=5.25MHz
	SPI_InitStructure.SPI_CPOL=SPI_CPOL_High;//CPOL=1
	SPI_InitStructure.SPI_CPHA=SPI_CPHA_2Edge;//第二个边沿开始采样,即CPHA=1
	SPI_InitStructure.SPI_NSS=SPI_NSS_Soft;//软件NSS模式
	SPI_InitStructure.SPI_CRCPolynomial=10;//CRC检测,不懂
	SPI_Init(SPI1,&SPI_InitStructure);
	
	DMA_InitTypeDef DMA_InitStructure;
	DMA_InitStructure.DMA_Channel=DMA_Channel_3;//选择DMA通道3
	DMA_InitStructure.DMA_Mode=DMA_Mode_Normal;//普通模式(非自动重装)
	DMA_InitStructure.DMA_DIR=DMA_DIR_MemoryToPeripheral;//转运方向为存储器到外设
	DMA_InitStructure.DMA_BufferSize=8;//数据传输量为8字节
	DMA_InitStructure.DMA_Priority=DMA_Priority_VeryHigh;//最高优先级
	DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)&(SPI1->DR);//外设地址(SPI1的DR数据接收寄存器)
	DMA_InitStructure.DMA_PeripheralBurst=DMA_PeripheralBurst_Single;//外设突发单次传输
	DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;//外设数据长度为1字节(8bits)
	DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//外设地址不自增
	DMA_InitStructure.DMA_Memory0BaseAddr=(uint32_t)BMI088_SPI_DMASend;//存储器地址(BMI088的SPI发送DMA存储器数组)
	DMA_InitStructure.DMA_MemoryBurst=DMA_MemoryBurst_Single;//存储器突发单次传输
	DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;//存储器数据长度为1字节(8bits)
	DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;//存储器地址自增
	DMA_InitStructure.DMA_FIFOMode=DMA_FIFOMode_Disable;//不使用FIFO模式
	DMA_InitStructure.DMA_FIFOThreshold=DMA_FIFOStatus_1QuarterFull;//设置FIFO阈值为1/4(不使用FIFO模式时,此位无意义)
	DMA_Init(DMA2_Stream3,&DMA_InitStructure);//初始化数据流3(SPI1发送DMA)
	
	DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralToMemory;//转运方向为外设到存储器
	DMA_InitStructure.DMA_Memory0BaseAddr=(uint32_t)BMI088_SPI_DMAReceive;//存储器地址(BMI088的SPI接收DMA存储器数组)
	DMA_Init(DMA2_Stream2,&DMA_InitStructure);//初始化数据流2(SPI1接收DMA)
	
	SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Tx,ENABLE);//使能SPI1的发送DMA搬运
	SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Rx,ENABLE);//使能SPI1的接收DMA搬运
	
	BMI088_CS_Accel(1);//复位CS1_Accel(加速度计片选引脚)
	BMI088_CS_Gyro(1);//复位CS1_Gyro(陀螺仪片选引脚)
		
	/*===============配置外部中断和SPI1接收DMA传输完成中断===============*/
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC,EXTI_PinSource4);//配置PC4与中断线的映射关系
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC,EXTI_PinSource5);//配置PC5与中断线的映射关系
	
	EXTI_InitTypeDef EXTI_InitStructure;
	EXTI_InitStructure.EXTI_Line=EXTI_Line4;//配置中断线4
	EXTI_InitStructure.EXTI_LineCmd=ENABLE;//使能中断线
	EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;//配置为外部中断模式
	EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;//选择下降沿触发
	EXTI_Init(&EXTI_InitStructure);//初始化EXTI
	EXTI_InitStructure.EXTI_Line=EXTI_Line5;//配置中断线5
	EXTI_Init(&EXTI_InitStructure);//初始化EXTI
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//选择NVIC分组为2
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel=EXTI4_IRQn;//配置NVIC通道4
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//使能NVIC通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;//响应优先级
	NVIC_Init(&NVIC_InitStructure);//初始化NVIC
	NVIC_InitStructure.NVIC_IRQChannel=EXTI9_5_IRQn;//配置NVIC通道9_5
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;//响应优先级
	NVIC_Init(&NVIC_InitStructure);//初始化NVIC
	
	DMA_ITConfig(DMA2_Stream2,DMA_IT_TC,ENABLE);//打通SPI1到NVIC的接收传输完成中断通道
		
	NVIC_InitStructure.NVIC_IRQChannel=DMA2_Stream2_IRQn;//选择SPI1接收DMA传输完成中断通道
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//使能中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//抢占优先级为1
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;//响应优先级为1
	NVIC_Init(&NVIC_InitStructure);//初始化SPI1接收DMA传输完成中断的NVIC
	
	/*===============使能===============*/
	DMA_Cmd(DMA2_Stream3,DISABLE);//失能DMA2的数据流3(SPI1发送DMA)
	DMA_Cmd(DMA2_Stream2,DISABLE);//失能DMA2的数据流2(SPI1接收DMA)
	SPI_Cmd(SPI1,ENABLE);//使能SPI1

	/*===============检测加速度计和陀螺仪ID并配置寄存器===============*/
	while(1)
	{
		if(BMI088_SPI_AccelReadRegister(BMI088_ACC_CHIP_ID)==BMI088_ACC_Address && BMI088_SPI_GyroReadRegister(BMI088_GYRO_CHIP_ID)==BMI088_GYRO_Address)//设备连接正常,加速度计和陀螺仪Who Am I正确
		{
			NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//关闭NVIC通道
			NVIC_Init(&NVIC_InitStructure);//初始化NVIC
			
			BMI088_SPI_AccelWriteRegister(BMI088_ACC_SOFTRESET,0xB6);BMI088_Delay_us(1000);//加速度计软重启,耗时1ms
			BMI088_SPI_GyroWriteRegister(BMI088_GYRO_SOFTRESET,0xB6);BMI088_Delay_us(30000);//陀螺仪软重启,耗时30ms
			
			BMI088_SPI_AccelReadRegister(BMI088_ACC_CHIP_ID);//再次读取ID,促使从机BMI088的SPI重新开始工作(软重启之后第一次读写有bug)
			BMI088_SPI_GyroReadRegister(BMI088_GYRO_CHIP_ID);
			
			BMI088_SPI_AccelWriteRegister(BMI088_ACC_PWR_CTRL,0x04);BMI088_Delay_us(300);//打开加速度计
			BMI088_SPI_AccelWriteRegister(BMI088_ACC_PWR_CONF,0x00);BMI088_Delay_us(300);//加速度计正常工作(不挂起)
			BMI088_SPI_AccelWriteRegister(BMI088_ACC_CONF,0xAB);BMI088_Delay_us(300);//配置加速度计正常低通滤波带宽,800Hz输出
			BMI088_SPI_AccelWriteRegister(BMI088_ACC_RANGE,0x00);BMI088_Delay_us(300);//配置加速度计量程±3g
			BMI088_SPI_AccelWriteRegister(BMI088_INT1_IO_CONF,0x08);BMI088_Delay_us(300);//配置加速度计INT1推挽输出,低电平有效(下降沿)
			BMI088_SPI_AccelWriteRegister(BMI088_INT1_INT2_MAP_DATA,0x04);BMI088_Delay_us(300);//配置INT1中断映射为数据就绪中断
			
			BMI088_SPI_GyroWriteRegister(BMI088_GYRO_RANGE,0x00);BMI088_Delay_us(300);//配置陀螺仪量程±2000°/s
			BMI088_SPI_GyroWriteRegister(BMI088_GYRO_BANDWIDTH,0x82);BMI088_Delay_us(300);//配置陀螺仪滤波器带宽116Hz,1000Hz输出(写此寄存器,写入数据最高位需要为1)
			BMI088_SPI_GyroWriteRegister(BMI088_GYRO_LPM1,0x00);BMI088_Delay_us(300);//配置陀螺仪主电源模式为正常模式
			BMI088_SPI_GyroWriteRegister(BMI088_GYRO_INT_CTRL,0x80);BMI088_Delay_us(300);//使能陀螺仪数据就绪中断
			BMI088_SPI_GyroWriteRegister(BMI088_INT3_INT4_IO_CONF,0x00);BMI088_Delay_us(300);//配置陀螺仪INT3推挽输出,低电平有效(下降沿)
			BMI088_SPI_GyroWriteRegister(BMI088_INT3_INT4_IO_MAP,0x01);BMI088_Delay_us(300);//配置INT3中断映射为数据就绪中断
			
			BMI088_FirstDMA_Flag=1;//准备首次启动DMA
			break;
		}
		else//设备异常
		{
			NVIC_InitStructure.NVIC_IRQChannelCmd=DISABLE;//关闭NVIC通道
			NVIC_Init(&NVIC_InitStructure);//初始化NVIC
			Warming_BMI088LinkError();//BMI088连接异常报警
		}
	}
	
	while(BMI088_DataStartFlag==0);//等待数据开始接收
}

/*
 *函数简介:BMI088处理加速度计数据
 *参数说明:无
 *返回类型:无
 *备注:本函数用于SPI接收DMA传输完成之后,数据来源为BMI088的SPI接收DMA存储器数组BMI088_SPI_DMAReceive
 *备注:加速度a(m2/s)=a_raw(g)*9.8=(a_raw/32768*Range)*9.8
 *					 =(a_raw/32768*3)*9.8
 *					 =a_raw*0.0008974358974
 */
void BMI088_ProcessAccelData(void)
{
	BMI088_RawAccelData[0]=(int16_t)((uint16_t)BMI088_SPI_DMAReceive[3]<<8|BMI088_SPI_DMAReceive[2]);//拼接为原始数据
	BMI088_RawAccelData[1]=(int16_t)((uint16_t)BMI088_SPI_DMAReceive[5]<<8|BMI088_SPI_DMAReceive[4]);
	BMI088_RawAccelData[2]=(int16_t)((uint16_t)BMI088_SPI_DMAReceive[7]<<8|BMI088_SPI_DMAReceive[6]);
	
	BMI088_Accel[0]=BMI088_RawAccelData[0]*0.0008974358974f;
	BMI088_Accel[1]=BMI088_RawAccelData[1]*0.0008974358974f;
	BMI088_Accel[2]=BMI088_RawAccelData[2]*0.0008974358974f;
//	BMI088_Accel[0]=BMI088_RawAccelData[0]/32768.0f*9.8f*3.0f;
//	BMI088_Accel[1]=BMI088_RawAccelData[1]/32768.0f*9.8f*3.0f;
//	BMI088_Accel[2]=BMI088_RawAccelData[2]/32768.0f*9.8f*3.0f;
}

/*
 *函数简介:BMI088处理温度数据
 *参数说明:无
 *返回类型:无
 *备注:本函数用于SPI接收DMA传输完成之后,数据来源为BMI088的SPI接收DMA存储器数组BMI088_SPI_DMAReceive
 *备注:温度t(℃)=t_raw*0.125+23
 *备注:温度数据是11bits数据
 */
void BMI088_ProcessTemperatureData(void)
{
	uint16_t unsignedTemperatureData=((uint16_t)BMI088_SPI_DMAReceive[2]<<3) | (BMI088_SPI_DMAReceive[3]>>5);//拼接为原始数据
	
	if(unsignedTemperatureData>1023)BMI088_RawTemperatureData=unsignedTemperatureData-2048;//对11bits数据进行正负数处理
	else BMI088_RawTemperatureData=unsignedTemperatureData;
	
	BMI088_Temperature=BMI088_RawTemperatureData*0.125f+23.0f;
}

/*
 *函数简介:BMI088处理陀螺仪数据
 *参数说明:无
 *返回类型:无
 *备注:本函数用于SPI接收DMA传输完成之后,数据来源为BMI088的SPI接收DMA存储器数组BMI088_SPI_DMAReceive
 *备注:角速度w(rad/s)=w_raw(°/s)/180*Π=(w_raw/32768*Range)/180*Π
 *					  =(w_raw/32768*2000)/180*Π
 *					  =w_raw*0.00106526443603169529841533860381
 */
void BMI088_ProcessGyroData(void)
{
	BMI088_RawGyroData[0]=(int16_t)((uint16_t)BMI088_SPI_DMAReceive[2]<<8|BMI088_SPI_DMAReceive[1]);//拼接为原始数据
	BMI088_RawGyroData[1]=(int16_t)((uint16_t)BMI088_SPI_DMAReceive[4]<<8|BMI088_SPI_DMAReceive[3]);
	BMI088_RawGyroData[2]=(int16_t)((uint16_t)BMI088_SPI_DMAReceive[6]<<8|BMI088_SPI_DMAReceive[5]);
	
	BMI088_Gyro[0]=BMI088_RawGyroData[0]*0.00106526443603169529841533860381f;
	BMI088_Gyro[1]=BMI088_RawGyroData[1]*0.00106526443603169529841533860381f;
	BMI088_Gyro[2]=BMI088_RawGyroData[2]*0.00106526443603169529841533860381f;
//	BMI088_Gyro[0]=BMI088_RawGyroData[0]/32768.0f*2000.0f/180.0f*3.141592653589793238462643383279f;
//	BMI088_Gyro[1]=BMI088_RawGyroData[1]/32768.0f*2000.0f/180.0f*3.141592653589793238462643383279f;
//	BMI088_Gyro[2]=BMI088_RawGyroData[2]/32768.0f*2000.0f/180.0f*3.141592653589793238462643383279f;
}

/*
 *函数简介:BMI088检测并关闭DMA
 *参数说明:无
 *返回类型:无
 *备注:用在外部中断中用来等待SPI传输结束后配合BMI088_OpenDMA函数重新启动DMA
 */
void BMI088_CheckAndCloseDMA(void)
{
	while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_BSY)==SET);//等待总线空闲
	while(DMA_GetFlagStatus(DMA2_Stream3,DMA_FLAG_TCIF3)==RESET);//判断发送完成
	DMA_ClearFlag(DMA2_Stream3,DMA_FLAG_TCIF3);//清除发送完成标志位
	while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_BSY)==SET);//等待总线空闲
	DMA_Cmd(DMA2_Stream3,DISABLE);//失能DMA2的数据流2
	DMA_Cmd(DMA2_Stream2,DISABLE);//失能DMA2的数据流3
}

/*
 *函数简介:BMI088开启DMA
 *参数说明:DMA传输数据个数
 *返回类型:无
 *备注:SPI收发DMA开启后会立刻开始发送接收,请在使用函数前配置BMI088的SPI发送DMA存储器数组BMI088_SPI_DMASend
 */
void BMI088_OpenDMA(uint8_t DMA_BufferSize)
{
	while(DMA_GetCmdStatus(DMA2_Stream2)!=DISABLE);//检测DMA2的数据流2为可配置状态
	DMA_SetCurrDataCounter(DMA2_Stream2,DMA_BufferSize);//恢复传输计数器的值
	DMA_Cmd(DMA2_Stream2,ENABLE);//使能DMA2的数据流2
	while(DMA_GetCmdStatus(DMA2_Stream3)!=DISABLE);//检测DMA2的数据流3为可配置状态
	DMA_SetCurrDataCounter(DMA2_Stream3,DMA_BufferSize);//恢复传输计数器的值
	DMA_Cmd(DMA2_Stream3,ENABLE);//使能DMA2的数据流3
}

/*
 *函数简介:BMI088加速度计外部中断中断函数
 *参数说明:无
 *返回类型:无
 *备注:在中断函数中启动DMA收发以实现减少CPU负担
 */
void EXTI4_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line4)==SET)//检测BMI088加速度计外部中断触发(即检测EXTI通道4中断触发)
	{
		EXTI_ClearITPendingBit(EXTI_Line4);//清除标志位
		
		if(BMI088_FirstDMA_Flag==0)//非第一次启动DMA
		{
			BMI088_CheckAndCloseDMA();//关闭DMA准备配置
			
			BMI088_Accel_Start();//片选加速度计
			BMI088_DMAAccGyroSelect=1;//DMA为加速度计数据接收
			BMI088_SPI_DMASend[0]=BMI088_ACC_AccelDataStart | 0x80;//配置SPI的发送数据的地址(读数据)
			
			BMI088_OpenDMA(8);//开启DMA转运8个数据
		}
		else if(BMI088_FirstDMA_Flag==1)//第一次启动DMA
		{
			BMI088_FirstDMA_Flag=0;
			
			BMI088_Accel_Start();//片选加速度计
			BMI088_DMAAccGyroSelect=1;//DMA为加速度计数据接收
			BMI088_SPI_DMASend[0]=BMI088_ACC_AccelDataStart | 0x80;//配置SPI的发送数据的地址(读数据)
			
			DMA_Cmd(DMA2_Stream2,ENABLE);//使能DMA2的数据流2
			DMA_Cmd(DMA2_Stream3,ENABLE);//使能DMA2的数据流3
		}
	}
}

/*
 *函数简介:BMI088陀螺仪外部中断中断函数
 *参数说明:无
 *返回类型:无
 *备注:在中断函数中启动DMA收发以实现减少CPU负担
 *备注:第一次DMA转运8个数据,从第二次DMA开始转运7个数据
 */
void EXTI9_5_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line5)==SET)//检测BMI088陀螺仪外部中断触发(即检测EXTI通道5中断触发)
	{
		EXTI_ClearITPendingBit(EXTI_Line5);//清除标志位
		
		if(BMI088_FirstDMA_Flag==0)//非第一次启动DMA
		{
			BMI088_CheckAndCloseDMA();//关闭DMA准备配置
			
			BMI088_Gyro_Start();//片选陀螺仪
			BMI088_DMAAccGyroSelect=2;//DMA为陀螺仪数据接收
			BMI088_SPI_DMASend[0]=BMI088_GYRO_GyroDataStart | 0x80;//配置SPI的发送数据的地址(读数据)
			
			BMI088_OpenDMA(7);//开启DMA转运7个数据
		}
		else if(BMI088_FirstDMA_Flag==1)//第一次启动DMA
		{
			BMI088_FirstDMA_Flag=0;	
			
			BMI088_Gyro_Start();//片选陀螺仪
			BMI088_DMAAccGyroSelect=2;//DMA为陀螺仪数据接收
			BMI088_SPI_DMASend[0]=BMI088_GYRO_GyroDataStart | 0x80;//配置SPI的发送数据的地址(读数据)
			
			DMA_Cmd(DMA2_Stream2,ENABLE);//使能DMA2的数据流2
			DMA_Cmd(DMA2_Stream3,ENABLE);//使能DMA2的数据流3
		}
	}
}

/*
 *函数简介:SPI1接收DMA传输完成中断中断函数
 *参数说明:无
 *返回类型:无
 *备注:在此函数中会处理接收数据获取BMI088的三轴加速度数据,三轴角速度数据和温度
 *备注:在此函数中如果接收的是加速度计数据会再开启一个DMA去接收温度数据
 */
void DMA2_Stream2_IRQHandler(void)
{
	if(DMA_GetITStatus(DMA2_Stream2,DMA_IT_TCIF2)==SET)//检测SPI1接收DMA传输完成中断触发
	{
		static uint8_t BMI088_ReceiveTEMPFlag=0;//BMI088的DMA接收温度数据标志位(0-未在接收温度数据,1-正在接收温度数据)
		BMI088_DataStartFlag=1;//数据开始接收
		DMA_ClearITPendingBit(DMA2_Stream2,DMA_IT_TCIF2);//清除标志位
		
		if(BMI088_ReceiveTEMPFlag==1)//正在接收温度数据
		{
			BMI088_Accel_Stop();//结束加速度计片选
			BMI088_ProcessTemperatureData();//处理温度数据
			BMI088_ReceiveTEMPFlag=0;
		}
		else//接收加速度或角速度数据
		{
			if(BMI088_DMAAccGyroSelect==1)//接收加速度计数据
			{
				BMI088_Accel_Stop();//结束加速度计片选
				BMI088_ProcessAccelData();//处理加速度数据
				
				BMI088_ReceiveTEMPFlag=1;//开始接收温度数据
				BMI088_CheckAndCloseDMA();//关闭DMA准备配置
				
				BMI088_Accel_Start();//片选加速度计
				BMI088_SPI_DMASend[0]=BMI088_ACC_TEMP_MSB | 0x80;//配置SPI的发送数据的地址(读数据)
				
				BMI088_OpenDMA(4);//开启DMA转运4个数据
			}
			else if(BMI088_DMAAccGyroSelect==2)//接收陀螺仪数据
			{
				BMI088_Gyro_Stop();//结束陀螺仪片选
				BMI088_ProcessGyroData();//处理陀螺仪数据
			}
		}
	}
}
